/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*                                                                           */
/*    Copyright (C) 2011 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    Driver for drvADXL345_ Acceleration sensor                             */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include <drvI2C.h>
#include <drvADXL345.h>
#include "drvIOConfig.h"

///////////////////////////////////////////////////////////////////////////////
// Macros
///////////////////////////////////////////////////////////////////////////////
// Constants
#define ADXL345_GENERATE_FUNCTION_NAME_PREFIX(x,y,z) x ## y ## z
#define ADXL345_I2C_Start(x,y,z)     ADXL345_GENERATE_FUNCTION_NAME_PREFIX(drv, x, Start)((y),(z))
#define ADXL345_I2C_WriteByte(x,y)   ADXL345_GENERATE_FUNCTION_NAME_PREFIX(drv, x, WriteByte)(y)
#define ADXL345_I2C_Restart(x,y,z)   ADXL345_GENERATE_FUNCTION_NAME_PREFIX(drv, x, Restart)((y),(z))
#define ADXL345_I2C_ReadByte(x,y)    ADXL345_GENERATE_FUNCTION_NAME_PREFIX(drv, x, ReadByte)(y)
#define ADXL345_I2C_Stop(x)          ADXL345_GENERATE_FUNCTION_NAME_PREFIX(drv, x, Stop)()

///////////////////////////////////////////////////////////////////////////////
// Local functions
static dosBool ADXLReadRegister(dosByte in_address, dosByte* out_value);
static dosBool ADXLWriteRegister(dosByte in_address, dosByte in_value);
static dosBool ADXLReadRegisterBlock(dosByte in_address, dosByte in_count, dosByte* out_value);

///////////////////////////////////////////////////////////////////////////////
// Initializes ADXL345
void drvADXL345Init(void)
{
	// initialize I2C bus
	InitADXL345I2C();
	
	// initialize chip
	ADXLWriteRegister(drvADXL345_BW_RATE, drvADXL345_BW_25);					//Set Output Rate to 100 Hz (bandwith 50Hz)
	ADXLWriteRegister(drvADXL345_DATAFORMAT, drvADXL345_DF_RANGE_2G | drvADXL345_DF_FULLRES );
	ADXLWriteRegister(drvADXL345_POWER_CTL, drvADXL345_MEASURE_MODE); //Put the Accelerometer into measurement mode   	
}

///////////////////////////////////////////////////////////////////////////////
//! Reads ADXL345 acceleration values
//! \param Acceleration in X axis
//! \param Acceleration in Y axis
//! \param Acceleration in Z axis
//! \return dosTrue if values were red successfully
dosBool drvADXL345ReadValues(dosWord* out_x, dosWord* out_y, dosWord* out_z)
{
	dosBool ack = dosFalse;

	ack = ADXL345_I2C_Start(ADXL345_I2C, drvI2C_WRITE, drvADXL345_ADDRESS);
  if( ack )
  {
		ADXL345_I2C_WriteByte(ADXL345_I2C, drvADXL345_DATAX0);
		ADXL345_I2C_Restart(ADXL345_I2C, drvI2C_READ, drvADXL345_ADDRESS);
   
		// read X value
		*out_x = ADXL345_I2C_ReadByte(ADXL345_I2C, drvI2C_ACK);
		*out_x |= ADXL345_I2C_ReadByte(ADXL345_I2C, drvI2C_ACK) << 8;
		
		// read Y value
		*out_y = ADXL345_I2C_ReadByte(ADXL345_I2C, drvI2C_ACK);
		*out_y |= ADXL345_I2C_ReadByte(ADXL345_I2C, drvI2C_ACK) << 8;

		// read Z value
		*out_z = ADXL345_I2C_ReadByte(ADXL345_I2C, drvI2C_ACK);
		*out_z |= ADXL345_I2C_ReadByte(ADXL345_I2C, drvI2C_NACK) << 8;
	}	
	ADXL345_I2C_Stop(ADXL345_I2C);
	
	return ack;
}

/*****************************************************************************/
/* Local functions                                                           */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Reads register of ADXL345 
dosBool ADXLReadRegister(dosByte in_address, dosByte* out_value)
{
	dosBool ack = ADXL345_I2C_Start(ADXL345_I2C, drvI2C_WRITE, drvADXL345_ADDRESS);
  if( ack )
  {
	 	ADXL345_I2C_WriteByte(ADXL345_I2C, in_address);
		ADXL345_I2C_Restart(ADXL345_I2C, drvI2C_READ, drvADXL345_ADDRESS);
		*out_value = ADXL345_I2C_ReadByte(ADXL345_I2C, drvI2C_NACK);
	}
	ADXL345_I2C_Stop(ADXL345_I2C);

	return ack;
}

///////////////////////////////////////////////////////////////////////////////
// Reads registers of ADXL345 
dosBool ADXLReadRegisterBlock(dosByte in_address, dosByte in_count, dosByte* out_value)
{
	dosByte value;
	dosByte i;
	
	dosBool ack = ADXL345_I2C_Start(ADXL345_I2C, drvI2C_WRITE, drvADXL345_ADDRESS);
	if( ack )
	{
 		ADXL345_I2C_WriteByte(ADXL345_I2C, in_address);
		ADXL345_I2C_Restart(ADXL345_I2C, drvI2C_READ, drvADXL345_ADDRESS);

		for(i = 0; i < in_count; i++)
		{
			value = ADXL345_I2C_ReadByte(ADXL345_I2C, (i==in_count-1)?drvI2C_NACK:drvI2C_ACK);
			out_value[i]= value;
		}
	}
	ADXL345_I2C_Stop(ADXL345_I2C);
	
	return ack;
}	

///////////////////////////////////////////////////////////////////////////////
// Writes ADXL345 register
dosBool ADXLWriteRegister(dosByte in_address, dosByte in_value)
{
	dosBool ack = ADXL345_I2C_Start(ADXL345_I2C, drvI2C_WRITE, drvADXL345_ADDRESS);
	if( ack )
	{
 		ADXL345_I2C_WriteByte(ADXL345_I2C, in_address);
 		ADXL345_I2C_WriteByte(ADXL345_I2C, in_value);
 	}	
	ADXL345_I2C_Stop(ADXL345_I2C);
	
	return ack;
}
